package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.atguigu.tingshu.album.mapper.*;
import com.atguigu.tingshu.album.service.AlbumAttributeValueService;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.album.service.AuditService;
import com.atguigu.tingshu.common.cache.RedisCache;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tencentcloudapi.cdwch.v20200915.models.ActionAlterCkUserRequest;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.sound.midi.Track;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

	@Autowired
	private AlbumInfoMapper albumInfoMapper;
	@Autowired
	private AlbumAttributeValueMapper albumAttributeValueMapper;
	@Autowired
	private BaseAttributeMapper baseAttributeMapper;
	@Autowired
	private BaseAttributeValueMapper baseAttributeValueMapper;
	@Autowired
	private AlbumAttributeValueService albumAttributeValueService;
	@Autowired
	private AlbumStatMapper albumStatMapper;
	@Autowired
	private TrackInfoMapper trackInfoMapper;
	@Autowired
	private AuditService auditService;
	@Autowired
	private RabbitService rabbitService;
	@Autowired
	private RedissonClient redissonClient;
	@Autowired
	private RedisTemplate redisTemplate;
	@Autowired
	private UserFeignClient userFeignClient;


	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveAlbumInfoVo(AlbumInfoVo albumInfoVo) {
		//保存albumInfo
		AlbumInfo albumInfo = new AlbumInfo();
		BeanUtils.copyProperties(albumInfoVo,albumInfo);
		//封装albumInfo对象
		//获取用户名
		Long userId = AuthContextHolder.getUserId();

		//设置专辑状态属性
		String payType = albumInfo.getPayType();
		//如果是vip免费
		if(SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType) || SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)){
			albumInfo.setTracksForFree(3);
		}
		//设置专辑审核状态
		albumInfo.setStatus(SystemConstant.ALBUM_STATUS_NO_PASS);

		//属性封装
		albumInfo.setUserId(userId);
		//数据库已对下面三条属性设置默认值
//		albumInfo.setIncludeTrackCount(0);
//		albumInfo.setIsFinished("0");
//		albumInfo.setQualityScore("0");
		albumInfoMapper.insert(albumInfo);
		//获取专辑id
		Long albumInfoId = albumInfo.getId();

//		//获取到所有的专辑状态数据(id,name)
//		List<BaseAttribute> baseAttributes = baseAttributeMapper.selectList(null);
//		Map<Long, String> baseAttrMap = baseAttributes.stream().collect(Collectors.toMap(
//				BaseAttribute::getId,
//				BaseAttribute::getAttributeName
//		));
//
//		//获取到所有的专辑状态值数据(id,name)
//		Map<Long, String> baseAttrValueMap = baseAttributeValueMapper.selectList(null).stream().collect(Collectors.toMap(
//				BaseAttributeValue::getId,
//				BaseAttributeValue::getValueName
//		));

		//插入专辑属性值数据
		List<AlbumAttributeValue> attributeValues = new ArrayList<>();
		List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
		if(!CollectionUtils.isEmpty(albumAttributeValueVoList)){
			for (AlbumAttributeValueVo attributeValueVo : albumAttributeValueVoList) {
				AlbumAttributeValue attributeValue = new AlbumAttributeValue();
				//封装属性
				attributeValue.setAlbumId(albumInfoId);
				attributeValue.setAttributeId(attributeValueVo.getAttributeId());
//				attributeValue.setAttributeName(baseAttrMap.get(attributeValueVo.getAttributeId()));
				attributeValue.setValueId(attributeValueVo.getValueId());
//				attributeValue.setValueName(baseAttrValueMap.get(attributeValueVo.getValueId()));
				attributeValues.add(attributeValue);
			}
			albumAttributeValueService.saveBatch(attributeValues);
		}

		//插入专辑状态值数据
		saveAlbumInfoStat(albumInfoId,SystemConstant.ALBUM_STAT_PLAY,0);
		saveAlbumInfoStat(albumInfoId,SystemConstant.ALBUM_STAT_SUBSCRIBE,0);
		saveAlbumInfoStat(albumInfoId,SystemConstant.ALBUM_STAT_BUY,0);
		saveAlbumInfoStat(albumInfoId,SystemConstant.ALBUM_STAT_COMMENT,0);

		// 对专辑中的文本内容进行审核
		String auditTextResult = auditService.auditText(albumInfo.getAlbumTitle() + albumInfo.getAlbumIntro());
		if("pass".equals(auditTextResult)){
			albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
			//审核通过发送MQ消息 通知 搜索服务 将专辑存入ES索引库
			rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_UPPER,albumInfoId);
		}else if("review".equals(auditTextResult)){
			albumInfo.setStatus(SystemConstant.ALBUM_STATUS_REVIEW);
		}else if("block".equals(auditTextResult)){
			albumInfo.setStatus(SystemConstant.ALBUM_STATUS_NO_PASS);
		}
		albumInfoMapper.updateById(albumInfo);
	}

	/**
	 * 保存专辑统计信息
	 *
	 * @param albumId  专辑ID
	 * @param statType 统计类型
	 * @param statNum  统计数值 0401-播放量 0402-订阅量 0403-购买量 0403-评论数'
	 */
	@Override
	public void saveAlbumInfoStat(Long alumId, String statType, int statNum){
		AlbumStat albumStat = new AlbumStat();
		albumStat.setAlbumId(alumId);
		albumStat.setStatType(statType);
		albumStat.setStatNum(statNum);
		albumStat.setCreateTime(new Date());
		albumStatMapper.insert(albumStat);
	}

	@Override
	public Page<AlbumListVo> findUserAlbumPage(Page<AlbumListVo> pageParam, AlbumInfoQuery albumInfoQuery) {
		Page<AlbumListVo> result = albumInfoMapper.findUserAlbumPage(pageParam,albumInfoQuery);

		return result;
	}

	@Override
	public void removeAlbumInfoById(Long id) {
		//根据id获取专辑,判断是否有此专辑
		AlbumInfo albumInfo = albumInfoMapper.selectById(id);
		if(albumInfo == null){
			return;
		}
		//因为专辑和声音表有关联,因此也要去声音表判断该专辑下是否有关联声音,如果有则不允许删除
		LambdaQueryWrapper<TrackInfo> trackInfoWrapper =
				new LambdaQueryWrapper<>();
		trackInfoWrapper.eq(TrackInfo::getAlbumId,id);
		Long count = trackInfoMapper.selectCount(trackInfoWrapper);
		if(count > 0){
			throw new GuiguException(500, "该专辑下存在关联声音");
		}

		//根据id删除专辑
		albumInfoMapper.deleteById(id);
		//删除专辑属性值数据
		LambdaQueryWrapper<AlbumAttributeValue> attributeValueWrapper =
				new LambdaQueryWrapper<>();
		attributeValueWrapper.eq(AlbumAttributeValue::getAlbumId,id);
		albumAttributeValueMapper.delete(attributeValueWrapper);
		//删除专辑状态数据
		LambdaQueryWrapper<AlbumStat> albumstatWrapper =
				new LambdaQueryWrapper<>();
		albumstatWrapper.eq(AlbumStat::getAlbumId, id);
		albumStatMapper.delete(albumstatWrapper);

		// 基于MQ删除存在Elasticsearch(全文搜索引擎)中数据
		rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_LOWER,id);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateAlbumInfo(Long id, AlbumInfoVo albumInfoVo) {
		//根据id判断是否存在此专辑
//		AlbumInfo albumInfo = albumInfoMapper.selectById(id);
//		if(albumInfo ==null){
//			return;
//		}
		AlbumInfo albumInfo = new AlbumInfo();
		//修改Album_Info表数据
		BeanUtils.copyProperties(albumInfoVo,albumInfo);
		albumInfo.setId(id);
		albumInfo.setStatus(SystemConstant.ALBUM_STATUS_NO_PASS); //修改审核状态为未通过
		albumInfo.setUpdateTime(new Date());
		albumInfoMapper.updateById(albumInfo);

		//修改专辑属性值数据
		//根据专辑id删除旧属性数据
		albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId,id));

		//插入专辑属性值数据
		List<AlbumAttributeValue> attributeValues = new ArrayList<>();
		List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
		if(!CollectionUtils.isEmpty(albumAttributeValueVoList)){
			for (AlbumAttributeValueVo attributeValueVo : albumAttributeValueVoList) {
				AlbumAttributeValue attributeValue = new AlbumAttributeValue();
				//封装属性
				attributeValue.setAlbumId(id);
				attributeValue.setAttributeId(attributeValueVo.getAttributeId());
				attributeValue.setValueId(attributeValueVo.getValueId());
				attributeValues.add(attributeValue);
			}
			albumAttributeValueService.saveBatch(attributeValues);
		}
		// 再次对内容进行审核
		// 对专辑中的文本内容进行审核
		String auditTextResult = auditService.auditText(albumInfo.getAlbumTitle() + albumInfo.getAlbumIntro());
		if("pass".equals(auditTextResult)){
			albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
			//审核通过发送MQ消息 通知 搜索服务 将专辑存入ES引库
			rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_UPPER,id);
		}else if("review".equals(auditTextResult)){
			albumInfo.setStatus(SystemConstant.ALBUM_STATUS_REVIEW);
			//发送MQ消息 通知 搜索服务 从ES引库中删除
			rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_LOWER,id);
		}else if("block".equals(auditTextResult)){
			albumInfo.setStatus(SystemConstant.ALBUM_STATUS_NO_PASS);
			//送MQ消息 通知 搜索服务 从ES引库中删除
			rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_LOWER,id);
		}
		albumInfoMapper.updateById(albumInfo);
	}

	@Override
	public List<AlbumInfo> findUserAllAlbumList(Long userId) {
		LambdaQueryWrapper<AlbumInfo> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(AlbumInfo::getUserId,userId) //根据用户id查询专辑
				.eq(AlbumInfo::getStatus,SystemConstant.ALBUM_STATUS_PASS) //只查询审核通过的
				.orderByDesc(AlbumInfo::getId) //按id排序
				.select(
						AlbumInfo::getId,
						AlbumInfo::getAlbumTitle
				) //只查询指定字段,并且搭配JsonInclude注解
				.last("limit 200"); //限制只查询200条数据(通常情况下同一个用户不会发布太多专辑,即便有,前端也应该是分页展示而非下拉框的形式展示)
		List<AlbumInfo> list = albumInfoMapper.selectList(wrapper);

		return list;
	}

	/**
	 * 根据专辑ID查询专辑信息（包括专辑标签列表）
	 * 通过Redisson分布式锁解决缓存击穿问题
	 *
	 * @param id 专辑ID
	 * @return 专辑信息
	 */
	@Override
	public AlbumInfo getAlbumInfoById(Long id) {
		try {
			//优先从缓存Redis中获取业务数据
			//构建key 前缀+专辑id
			String dataKey = RedisConstant.ALBUM_INFO_PREFIX + id;
			AlbumInfo albumInfo = (AlbumInfo) redisTemplate.opsForValue().get(dataKey);
			//查询缓存中的专辑信息
			if(albumInfo != null){
				//如果命中缓存,则之间返回即可
				return albumInfo;
			}

			//如果未命中缓存,先获取分布式锁,构建当前业务数据锁的key 业务key+锁的后缀
			//尝试获取分布式锁
			String lockKey = dataKey + RedisConstant.CACHE_LOCK_SUFFIX;
			RLock lock = redissonClient.getLock(lockKey);

			//lock.lock();
			//param1:等待锁获取最大时间 param2:锁过期时间 param3:时间单位  获取锁失败返回false
			boolean isLock = lock.tryLock(RedisConstant.ALBUM_LOCK_WAIT_PX1, RedisConstant.ALBUM_LOCK_EXPIRE_PX2, TimeUnit.SECONDS);
			if(isLock){
				try {
					//如果上锁成功,从数据库中查询(回源查询)
					AlbumInfo albumInfoByIdFromDB = this.getAlbumInfoByIdFromDB(id);
					int ttl = RandomUtil.randomInt(100, 600);
					redisTemplate.opsForValue().set(dataKey,albumInfoByIdFromDB,RedisConstant.ALBUM_TIMEOUT + ttl,TimeUnit.SECONDS);
					return albumInfoByIdFromDB;
				} catch (Exception e) {
					throw new RuntimeException(e);
				} finally {
					//释放分布式锁
					lock.unlock();
				}
			}else{
				//获取锁失败,睡眠+自旋
				TimeUnit.SECONDS.sleep(20);
				return this.getAlbumInfoById(id);
			}
		} catch (Exception e) {
			log.error("[专辑服务]获取专辑信息锁服务异常异常：{},执行兜底处理方案：{}", e, "直接查询数据库");
			return this.getAlbumInfoByIdFromDB(id);
		}
	}

	@Override
	@RedisCache(prefix = RedisConstant.ALBUM_INFO_PREFIX)
	public AlbumInfo getAlbumInfoByIdFromDB(Long id) {
		AlbumInfo albumInfo = albumInfoMapper.selectById(id);
		if(albumInfo == null){
			return null;
		}
		//根据专辑Id查询专辑标签属性列表
		List<AlbumAttributeValue> attributeValues = albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>()
				.eq(AlbumAttributeValue::getAlbumId, id));
		albumInfo.setAlbumAttributeValueVoList(attributeValues);
		return albumInfo;
	}

	@Override
	@RedisCache(prefix = RedisConstant.ALBUM_INFO_PREFIX + ":stat:")
	public AlbumStatVo getAlbumStatVo(Long albumId) {
		AlbumStatVo albumStatVo = albumInfoMapper.getAlbumStatVo(albumId);

		return albumStatVo;
	}

	/**
	 * 基于当前选择购买起始声音得到分集购买列表
	 *
	 * @param trackId
	 * @return [{name:"本集",price:1,trackCount:1},{name:"后10集",price:10,trackCount:10}...{name:"全集/45集",price:45,trackCount:45}]
	 */
	@Override
	public List<Map<String, Object>> findUserTrackPaidList(Long userId, Long trackId) {
		//根据声音id获取到当前声音在专辑中的序号和专辑id
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		Integer orderNum = trackInfo.getOrderNum();
		Long albumId = trackInfo.getAlbumId();
		//获取到从当前序号开始的的专辑
		List<TrackInfo> trackInfoList = trackInfoMapper.selectList(
				new LambdaQueryWrapper<TrackInfo>()
						.eq(TrackInfo::getAlbumId, albumId)
						.ge(TrackInfo::getOrderNum, orderNum)
						.select(TrackInfo::getId)
		);
		//调用远程服务查看当前用户已购买的当前专辑中的声音
		List<Long> alreadPaidTrackList = userFeignClient.findUserPaidTrackList(albumId).getData();

		//未购买声音数量
		int size = trackInfoList.size();
		//过滤得到未购买的声音id
		if(!CollectionUtils.isEmpty(alreadPaidTrackList)){
			List<Long> wairPaidTrackList = trackInfoList.stream().filter(f -> !alreadPaidTrackList.contains(f.getId()))
					.map(TrackInfo::getId)
					.collect(Collectors.toList());
			size = wairPaidTrackList.size();
		}
		//基于未购买声音数量， 动态封装分集购买列表
		List<Map<String,Object>> list = new ArrayList<>();
		//查询专辑信息得到单集价格
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
		BigDecimal price = albumInfo.getPrice();
		//创建"当前集"分集购买对象
		Map<String,Object> currMap = new HashMap<>();
		currMap.put("price",price);
		currMap.put("name","当前集");
		currMap.put("trackCount",1);
		list.add(currMap);
		//创建"后i*10集"分集购买对象
		for (int i = 10; i <= 50; i+=10) {
			Map<String,Object> map = new HashMap<>();
			if(i < size){
				map.put("price",price.multiply(new BigDecimal(i)));
				map.put("name","后" + i + "集");
				map.put("trackCount",i);
				list.add(map);
			}else{
				map.put("price",price.multiply(new BigDecimal(size)));
				map.put("name","后" + size + "集");
				map.put("trackCount",size);
				list.add(map);
				break;
			}
		}
		return list;
	}


}
